﻿using System;

namespace Rules
{
    public abstract class RuleBase<T> : IRule
    {
        protected RuleBase(string propertyName)
            : this(propertyName, string.Empty) { }

        protected RuleBase(string propertyName, string description)
        {
            PropertyName = propertyName;
            Description = description;
        }

        private string _propertyName;
        public string PropertyName
        {
            get
            {
                return _propertyName;
            }
            private set
            {
                ValidateNotNull(value, "PropertyName");
                _propertyName = value;
            }
        }

        private string _description;
        public string Description
        {
            get
            {
                if (string.IsNullOrEmpty(_description))
                    return GetDefaultDescription();
                else
                    return _description;
            }
            private set
            {
                _description = value;
            }
        }

        public bool IsValid { get; private set; }

        public object Subject { get; private set; }

        public bool Evaluate(object subject)
        {
            Subject = subject;
            IsValid = DoEvaluate((T)subject);
            return IsValid;
        }

        protected abstract bool DoEvaluate(T subject);

        protected abstract string GetDefaultDescription();

        private void ThrowInvalidCastException(object toConvert)
        {
            string message = "Cannot convert {0} to {1}";
            message = string.Format(message, toConvert.GetType().Name, typeof(T).Name);
            throw new InvalidCastException(message);
        }

        protected void ValidateNotNull(object toValidate, string paramName)
        {
            if (toValidate == null || string.Empty.Equals(toValidate))
                throw new ArgumentNullException(paramName);
        }
    }
}